package com.mytx.sso.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.annotation.SerializedField;
import com.mytx.common.config.MytxConfig;
import com.mytx.common.constant.Constant;
import com.mytx.common.pojo.CommonResult;
import com.mytx.common.utils.EntityUtils;
import com.mytx.common.utils.IDUtils;
import com.mytx.common.utils.JwtTokenUtils;
import com.mytx.common.utils.Utils;
import com.mytx.mapper.ContactMapper;
import com.mytx.mapper.UserMapper;
import com.mytx.pojo.*;
import com.mytx.sso.service.ConsumerSearchService;
import com.mytx.sso.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;


@SuppressWarnings({"SpringJavaInjectionPointsAutowiringInspection", "Duplicates"})
@RestController
public class UserController implements UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);


    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ContactMapper contactMapper;



    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ConsumerSearchService searchService;

    @Autowired
    private HttpServletRequest request;
    @Value("${password_error_count_expire}")
    Integer passwordErrorCountExpire; //登录密码错误计数周期，单位：分钟
    @Value(("${login_error_limit}"))
    Integer loginErrorLimit;//一个计数周期内的登录错误次数上限 ,
    @Value(("${retrieve_pay_password_error_limit}"))
    Integer retrievePayPasswordErrorLimit;//一个计数周期内的通过登录密码找回支付密码次数上限

    @Value("${account_lock_expire}")
    Integer accountLockExpire;// 账户锁定时间 单位：小时

    @Override

    /**
     * 注册用户
     */
    public CommonResult restRegister(@RequestParam("mobileCode") String mobileCode, @RequestBody User user) {

        String phone = user.getPhone();
        logger.info("restRegister:新用户注册信息" + phone);
        // 验证该手机号是否已经注册，避免用户 拿已经注册了的手机号，在找回密码等接口获取验证码后，又拿来作为注册的验证码

        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        //根据客户端携带的信息，构造查询数据
        criteria.andPhoneEqualTo(phone);
        List<User> list = userMapper.selectByExample(example);
        if (list != null && list.size() != 0) {
            logger.error("restRegister:该号码已经被注册   " + phone);
            return CommonResult.build(Constant.SEND_MOBILE_CODE_FAIL_ENGAGED, "该号码已经被注册");
        }

        //验证短信验证码是否正确
        CommonResult result = checkMobileCode(mobileCode, phone);
        if (result != null) return result;
        user.setuId(IDUtils.genUUID());
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        user.setCreated(new Date());
        userMapper.insertSelective(user);


        //将注册的用户信息放入到第三方服务上面
        registerThirdPartyService(user, phone);
        String salt = Utils.genSalt();//生成 盐
        String token = JwtTokenUtils.genToken(salt, user.getuId());
        user.setSalt(salt);
        user.setCreated(null);//清掉用不着缓存的用户信息
        saveUserInfoToRedis(user);
        redisTemplate.expire(Constant.USER_SESSION + user.getuId(), 30, TimeUnit.DAYS);//设置登录用户信息缓存过期时间
        //返回用户数据之前，清理掉用不着返回app的字段
        user.setPassword(null);
        user.setSalt(null);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("userInfo", user);
        resultMap.put("token", token);
        return CommonResult.ok(resultMap);
    }


    /**
     * 用户登录
     * @param user
     * @return
     */
    @Override
    // @SerializedField(encrypt = false)
    public CommonResult restLogin(@RequestBody User user) {
        String phoneNumber = user.getPhone();
        logger.info("账户密码登录：" + phoneNumber);
        // User user = requestBody.getObject("ct", User.class);
        if (user == null) {
            return CommonResult.build(400, "error", "数据为空");
        }
        //查询redis,看该 手机号 是否因连续登录错误，被禁止登录
        Object loginCountObject = redisTemplate.opsForValue().get("LOGIN_COUNT:" + phoneNumber);

        if (loginCountObject != null) {
            int loginCount = (int) loginCountObject;
            if (loginCount > loginErrorLimit) {
                logger.warn("restLogin:登录密码错误超过限制，账户进入锁定状态  " + phoneNumber);
                Long expire = redisTemplate.getExpire("LOGIN_COUNT:" + phoneNumber, TimeUnit.MINUTES);
                return CommonResult.build(Constant.LOGIN_ERROR_LIMIT, String.format("连续登录尝试超过%s次限制", loginErrorLimit), expire);
            } else if (loginCount == loginErrorLimit) {
                // 当错误登录次数等于限制次数的时候，把错误次数设置为 错误次数上限+1，过期时间设置为 预设的 账户锁定时间
                logger.warn("restLogin:登录密码错误超过限制，账户进入锁定状态  " + phoneNumber);
                redisTemplate.opsForValue().set("LOGIN_COUNT:" + phoneNumber, (loginErrorLimit + 1), accountLockExpire, TimeUnit.HOURS);
                return CommonResult.build(Constant.LOGIN_ERROR_LIMIT, String.format("连续登录尝试超过%s次限制", loginErrorLimit), accountLockExpire * 60);
            }
        }


        //根据电话号码查询数据库
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        //根据客户端携带的信息，构造查询数据
        if (StringUtils.isNotBlank(phoneNumber)) {
            criteria.andPhoneEqualTo(phoneNumber);
        } else if (StringUtils.isNotBlank(user.getUsername())) {
            criteria.andUsernameEqualTo(user.getUsername());
        } else if (StringUtils.isNotBlank(user.getEmail())) {
            criteria.andEmailEqualTo(user.getEmail());
        }
        //criteria.andPasswordEqualTo(DigestUtils.md5DigestAsHex(tbUser.getPassword().getBytes()));
        List<User> list = userMapper.selectByExample(example);
        if (list == null || list.size() == 0) {
            return CommonResult.build(Constant.USER_NAME_INVALID, "没有该用户信息");
        }
        User dataBaseUser = list.get(0);
        if (!dataBaseUser.getPassword().equals(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()))) {
            //当登录失败，记录该手机号登录次数，
            Long loginErrorCount = 1L;
            if (loginCountObject == null) {//第一次登录错误
                redisTemplate.opsForValue().set("LOGIN_COUNT:" + phoneNumber, 1, passwordErrorCountExpire, TimeUnit.MINUTES);
            } else {
                loginErrorCount = redisTemplate.opsForValue().increment("LOGIN_COUNT:" + phoneNumber, 1);
            }

            return CommonResult.build(Constant.PASS_WORD_WRONG, "密码错误", loginErrorLimit - loginErrorCount);
        }

        String salt = Utils.genSalt();
        String token = JwtTokenUtils.genToken(salt, dataBaseUser.getuId());

        dataBaseUser.setSalt(salt);
        //缓存用户信息到Redis
        // redisTemplate.opsForValue().set(redisKeyConfig.USER_SESSION + dataBaseUser.getuId(), JSONObject.toJSONString(dataBaseUser), 30, TimeUnit.DAYS);//以前是序列化成json,保存成string
        dataBaseUser.setCreated(null);
        dataBaseUser.setUpdated(null);
        saveUserInfoToRedis(dataBaseUser);
        redisTemplate.expire(Constant.USER_SESSION + dataBaseUser.getuId(), 30, TimeUnit.DAYS);//设置登录用户信息缓存过期时间
        dataBaseUser.setPassword(null);//清空密码
        dataBaseUser.setPayPassword(null);
        dataBaseUser.setSalt(null);
        //生成顽兔token
        Map<String, Object> versionInfo = getVersionInfo();
        //查询mysql中的联系人
        List<Contact> contacts = contactMapper.queryContacts(dataBaseUser.getuId());
        //当前登录的用户在tid时，将tGroupName设置为GroupName
        //当前登录的用户在tid时，将tLocation设置为location
        mappingGroupName(contacts,dataBaseUser.getuId());
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", token);
        resultMap.put("userInfo", dataBaseUser);
        resultMap.put("contacts", contacts);
        resultMap.put("versionInfo", versionInfo);//在登录和自动登录的同时，返回版本信息
//        try {
//            RSAUtil.encrypt(resultMap.toString().getBytes(),cilentPublicKey);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return CommonResult.build(401,"加密错误");
//
        return CommonResult.ok(resultMap);

    }

    private Map<String, Object> getVersionInfo() {
        Map<String, Object> versionInfo = new HashMap<>();//返回版本信息
        versionInfo.put("version", MytxConfig.version);
        versionInfo.put("updateLog", MytxConfig.updateLog);
        versionInfo.put("apk_url",MytxConfig.apkUrl);
        return versionInfo;
    }



    /**
     * 自动登录
     * @return
     */
    @Override
    //@SerializedField(encrypt = false,addEncodeFlag = true)
    public CommonResult autoLogin() {

        String uId = request.getHeader("uId");
        logger.info("自动登录：" + uId);
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + uId);
        User user = JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
        user.setPassword(null);//清空密码
        user.setPayPassword(null);
        user.setSalt(null);
        //查询mysql中的联系人
        // List<Contact> contacts = contactMapper.queryContacts(uId);
        Map<String, Object> versionInfo = getVersionInfo();
        JSONObject result = new JSONObject();
        result.put("userInfo", user);
        result.put("versionInfo", versionInfo);
        return CommonResult.ok(result);

    }

    /**
     * 因为请求的时候携带token,所以app请求的时候是加密的，app一次完整请求的 请求体、响应体是否需要加密和解密，是关联的，请求加密，那响应对应就会做解密操作，
     * 这点是在app定义的，后续修改成返回数据是否加密由服务端指定，给在回传数据中，标识出数据是否需要解密，让app 根据标识做响应的动作
     * 所以 登出也只好加密返回，其实没有任何重要数据
     *
     * @return
     */
    @PostMapping("/logout_v1")
    public CommonResult logout() {
        //  String uId = request.getHeader("uId");
        String uId = request.getHeader("uId");
        redisTemplate.delete(Constant.USER_SESSION + uId);
        logger.info("用户登出：" + uId);
        return CommonResult.ok();
    }


    /**
     * 修改密码方法，不携带token ,用户信息只能去 mysql 查询
     *
     * @param body
     * @return
     */
    @PostMapping("/modifyPassword")
    public CommonResult modifyPassword(@RequestBody JSONObject body) {

        String phoneNumber = body.getString("phoneNumber");
        logger.info("modifyPassword:" + phoneNumber);
        String mobileCode = body.getString("mobileCode");
        String password = body.getString("password");
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        CommonResult result = checkMobileCode(mobileCode, phoneNumber);
        if (result != null) {//返回结果不为空，说明验证失败，直接返回验证结果
            return result;
        }
        // 短信验证通过，根据手机号查询 账户，替换
        //根据电话号码查询数据库
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        criteria.andPhoneEqualTo(phoneNumber);
        List<User> users = userMapper.selectByExample(example);
        if (users != null && users.size() != 0) {
            User user = users.get(0);
            user.setPassword(password);
            user.setUpdated(new Date());
            userMapper.updateByPrimaryKeySelective(user);
            redisTemplate.opsForHash().put(Constant.USER_SESSION + user.getuId(), "password", password);//因为用户修改密码，可能是未登录情况下，也可能是登录的情况下，所以需要缓存用户 修改后的密码
            redisTemplate.delete("LOGIN_COUNT:" + phoneNumber);// 清除账户登录错误记录，避免出现用户账户因为连续输错密码被锁定后，修改了密码还无法登录的情况
            //当用户修改密码后，缓存用户修改密码记录，24小时后到期自动删除，是为了保护账户，在24小时内通过短信验证修改过登录密码的账户，禁止修改绑定的手机号和通过登录密码重置支付密码
            redisTemplate.opsForValue().set("MODIFY_PASSWORD:" + user.getuId(), "1", 24, TimeUnit.HOURS);

            return CommonResult.ok();
        } else {
            return CommonResult.build(Constant.PHONE_NUMBER_INVALID, "该号码尚未绑定任何账户");//这个情况应该不存在，因为在发送短信验证码的时候，查询过数据库，不存在的号码，是不给发短信验证码的
        }

    }


    /**
     * 更新数据到 数据库和阿里云旺
     * 方法参数必须带上@RequestBody  否则参数无法接收到..
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/upDateUser", method = RequestMethod.POST)
    public User upDateUserInfo(@RequestBody User user) {
        //更新信息到数据库
        userMapper.updateByPrimaryKeySelective(user);
        //当更新的信息不含有以下信息时候，直接return,不推送信息告诉联系人自己信息已经更改了
        if (StringUtils.isBlank(user.getAvatar()) && StringUtils.isBlank(user.getUsername())
                && StringUtils.isNotBlank(user.getPhone()) && StringUtils.isNotBlank(user.getArea())
                && user.getGender() == null) {
            return user;
        }

        if (StringUtils.isNotBlank(user.getAvatar()) || StringUtils.isNotBlank(user.getUsername())
                || StringUtils.isNotBlank(user.getPhone())) {
            Topic userInfoTopic = new Topic();
            userInfoTopic.setId(user.getuId());
            //现在在质保了3个用户信息字段到es,如果后续要保存更多用户信息到es 的话，这儿需要改写
            User saveToES = new User(user.getuId());
            saveToES.setAvatar(user.getAvatar());
            saveToES.setPhone(user.getPhone());
            saveToES.setUsername(user.getUsername());
            userInfoTopic.setManager(saveToES);
            searchService.update(userInfoTopic);
            logger.info("联系人更新到es成功:uId:{}" + user.getuId());
        }
        //推送信息给双边关系（status=2）的联系人，告诉他们自己信息更新了
        List<Contact> contacts = contactMapper.queryContacts(user.getuId());
        if (contacts == null || contacts.size() == 0) {
            return user;
        }
        List<String> userIdList = addFrindUserMessage(contacts,user.getuId());
        Message notify = new Message();
        notify.setType(Constant.PUSH_MESSAGE_CONTACT_USER_INFO_CHANGE);
        notify.setExtraData(user);
        notify.setCreated(new Date());
        pushMessage(userIdList, notify);
        return user;
    }

    /**
     * 物理删除数据库ES和阿里云旺的用户信息
     * 方法参数必须带上@RequestBody  否则参数无法接收到..
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/deleteUserInfo", method = RequestMethod.POST)
    public User deleteUserInfo(@RequestBody User user) {
        //1.根据uid删除数据库中的信息
        String uId = user.getuId();
        int count = userMapper.deleteByPrimaryKey(uId);
        if (count > 0) {
            //数据库中的数据删除成功,才删除第三方服务的用户数据
            //2.根据uid删除redis中的信息
            Boolean isDelete = redisTemplate.delete(Constant.USER_SESSION + uId);
            if (isDelete) {
                logger.info("deleteUserInfo:根据uid删除redis中的信息成功:uId:{}", uId);
            } else {
                logger.error("deleteUserInfo:根据uid删除redis中的信息失败:uId:{}", uId);
            }
            //3.根据uid删除ES中的用户信息
            Map<String, Object> info = new HashMap<>();
            info.put("id", uId);
            CommonResult searchResult = searchService.delete(info);
            Integer resStatus = searchResult.getStatus();
            //判断ES是否删除成功
            if (!Constant.RETURN_HTTP_STATUS_SUCCESS.equals(resStatus)) {
                logger.error("根据uid删除ES中的信息失败:uId:{},retCode:{},errorMsg:{}", uId, resStatus, searchResult.getMsg());
            } else {
                logger.info("根据uid删除ES中的信息成功:uId:{}", uId);
            }
        }
        return user;
    }



    /**
     * 授权用户绑定手机账号
     *
     * @param body
     * @return
     */
    @RequestMapping(value = "/userBindAccount", method = RequestMethod.POST)
    public CommonResult userBindAccount(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        //获取绑定的信息
        User bindUser = body.getObject("userInfo", User.class);
        logger.info("userBindAccount：绑定的账户:uId:{}", uId);
        bindUser.setuId(uId);
        String fromPassword = bindUser.getPassword();
        bindUser.setPassword(DigestUtils.md5DigestAsHex(fromPassword.getBytes()));
        //        String uId  = bindUser.getuId();
        String mobileCode = body.getString("mobileCode");
        //验证短信是否正确
        CommonResult result = checkMobileCode(mobileCode, bindUser.getPhone());
        if (result != null) {
            return result;
        }
        //判断授权用户绑定的手机号是否为注册用户
        String phone = bindUser.getPhone();
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        criteria.andPhoneEqualTo(phone);
        List<User> users = userMapper.selectByExample(example);
        if (users != null && users.size() > 0) {
            //当前绑定的手机号已经被注册过了,将授权用户信息同步到注册用户信息上
            logger.info("绑定的手机号:phone:{}已经被注册过了,现在开始同步数据....", phone);
            User originalUserInfo = users.get(0); //注册的用户
            User authUser = getUser(uId);
            String originalUserId = originalUserInfo.getuId();
            //同步基本字段信息
            authSetOriginalUser(authUser,originalUserInfo,bindUser);
            //同步收货地址信息
            List<OrderReceiveInfo> registerOrderReceiveInfoList = originalUserInfo.getOrderReceiveInfos(); //注册用户收货地址
            List<OrderReceiveInfo> authUserOrderReceiveInfoList = authUser.getOrderReceiveInfos();//授权用户收货地址
            if (registerOrderReceiveInfoList == null) {
                registerOrderReceiveInfoList = authUserOrderReceiveInfoList;
            } else {
                registerOrderReceiveInfoList.addAll(authUserOrderReceiveInfoList);
            }
            originalUserInfo.setOrderReceiveInfos(registerOrderReceiveInfoList);
            logger.info("绑定的手机号:phone:{}已经被注册过了,同步数据完成....", phone);
            //更新注册用户的信息
            upDateUserInfo(originalUserInfo);
            List<Contact> registerContacts = contactMapper.queryContacts(originalUserId);//获取绑定注册用户的联系人信息
            mappingGroupName(registerContacts,originalUserId);
            //删除授权用户的信息
            deleteUserInfo(authUser);
            //重新生成token返回到客户端
            String bindSalt = Utils.genSalt();
            String token = JwtTokenUtils.genToken(bindSalt, originalUserId);
            logger.info("重新生成token成功,token:{},uId:{},salt:{}", token, originalUserId, bindSalt);
            originalUserInfo.setSalt(bindSalt);
            Map map = EntityUtils.objectToMap_v1(originalUserInfo);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + originalUserId, map);
            logger.info("更新redis中的数据成功....");
            //将敏感字段设置为空
            originalUserInfo.setPassword(null);
            originalUserInfo.setPayPassword(null);
            originalUserInfo.setSalt(null);
            //物理删除授权用户的信息
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("userInfo", originalUserInfo);
            resultMap.put("token", token);
            resultMap.put("contacts", registerContacts);
            return CommonResult.ok(resultMap);
        }
        //将设置的密码和手机号同步到redis中
        Map beanMap = EntityUtils.objectToMap_v1(bindUser);
        redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, beanMap);
        //将信息修改到数据库和第三方服务上
        logger.info("将绑定的信息同步到数据库和第三方服务上 uid:{}username:{},phone:{}", uId, bindUser.getUsername(), bindUser.getPhone());
        User tableUser = upDateUserInfo(bindUser);
        //将敏感字段设置为空
        tableUser.setPassword(null);
        tableUser.setPayPassword(null);
        tableUser.setSalt(null);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("userInfo", tableUser);
        return CommonResult.ok(resultMap);
    }

    /**
     * 授权用户设置手机号和密码
     *
     * @param body
     * @return
     */
//    @RequestMapping(value = "/userBindAccount",method = RequestMethod.POST)
    public CommonResult userBindPhoneAccount(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        //获取绑定的信息
        User bindUser = body.getObject("userInfo", User.class);
        logger.info("userBindAccount：绑定的账户:uId:{}", uId);
        bindUser.setuId(uId);
        String fromPassword = bindUser.getPassword();
        bindUser.setPassword(DigestUtils.md5DigestAsHex(fromPassword.getBytes()));
        //        String uId  = bindUser.getuId();
        String mobileCode = body.getString("mobileCode");
        //验证短信是否正确
        CommonResult result = checkMobileCode(mobileCode, bindUser.getPhone());
        if (result != null) {
            return result;
        }
        //判断授权用户绑定的手机号是否为注册用户
        String phone = bindUser.getPhone();
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        criteria.andPhoneEqualTo(phone);
        List<User> users = userMapper.selectByExample(example);
        if (users != null && users.size() > 0) {
            //当前绑定的手机号已经被注册过了,将注册用户的信息同步到授权用户信息上
            logger.info("绑定的手机号:phone:{}已经被注册过了,现在开始同步数据....", phone);
            User register = users.get(0); //注册的用户
            User authUser = userMapper.selectByPrimaryKey(uId); //授权用户信息
            authUser.setPhone(phone);
            //同步基本字段信息
            BigDecimal authBalace = authUser.getBalance();
            BigDecimal registerBalace = register.getBalance();
            BigDecimal authDeposit = authUser.getDeposit();
            BigDecimal registerDeposit = register.getDeposit();
            logger.info("注册用户的余额:registerBalace:{},注册用户的保证金:registerDeposit:{}", registerBalace, registerDeposit);
            logger.info("授权用户的余额:authBalact:{},注册用户的保证金:authDeposit:{}", authBalace, authDeposit);
            authUser.setBalance(authBalace.add(registerBalace));
            authUser.setDeposit(authDeposit.add(registerDeposit));
            authUser.setUsername(bindUser.getUsername());
            authUser.setPassword(DigestUtils.md5DigestAsHex(fromPassword.getBytes()));
            if (authUser.getPayPassword() == null) {
                authUser.setPayPassword(register.getPayPassword());
            }
            if (authUser.getPayLimit() == null) {
                authUser.setPayLimit(register.getPayLimit());
            }
            BigDecimal authDonationAmount = authUser.getDonationAmount();
            BigDecimal registerDonationAmout = register.getDonationAmount();
            BigDecimal authDonationBalance = authUser.getDonationBalance();
            BigDecimal registerDonationBalance = register.getDonationBalance();
            BigDecimal authDonationReceived = authUser.getDonationReceived();
            BigDecimal registerDonationReceived = register.getDonationReceived();
            logger.info("注册用户的registerDonationAmout:{},注册用户的registerDonationBalance:{},注册用户的registerDonationReceived:{}",
                    registerDonationAmout, registerDonationBalance, registerDonationReceived);
            logger.info("授权用户的authDonationAmout:{},授权用户的authDonationBalance:{},授权用户的authDonationReceived:{}",
                    authDonationAmount, authDonationBalance, authDonationReceived);
            authUser.setDonationAmount(authDonationAmount.add(registerDonationAmout));
            authUser.setDonationBalance(authDonationBalance.add(registerDonationBalance));
            authUser.setDonationReceived(authDonationReceived.add(registerDonationReceived));
            if (authUser.getEmail() == null) {
                authUser.setEmail(register.getEmail());
            }
            authUser.setCreated(register.getCreated());
            authUser.setUpdated(new Date());
            //同步收货地址信息
            List<OrderReceiveInfo> registerOrderReceiveInfoList = register.getOrderReceiveInfos(); //注册用户收货地址
            List<OrderReceiveInfo> authUserOrderReceiveInfoList = authUser.getOrderReceiveInfos();//授权用户收货地址
            if (registerOrderReceiveInfoList != null && registerOrderReceiveInfoList.size() > 0) {
                if (authUserOrderReceiveInfoList == null) {
                    authUserOrderReceiveInfoList = new ArrayList<>();
                }
                for (OrderReceiveInfo orderReceiveInfo : registerOrderReceiveInfoList) {
                    authUserOrderReceiveInfoList.add(orderReceiveInfo);
                }
            }
            authUser.setOrderReceiveInfos(authUserOrderReceiveInfoList);
            logger.info("绑定的手机号:phone:{}已经被注册过了,同步数据完成....", phone);
            //更新授权用户的信息
            upDateUserInfo(authUser);
            //同步联系人信息
            String registerUid = register.getuId();
            List<Contact> registerContacts = contactMapper.queryContacts(registerUid);//获取绑定注册用户的联系人信息
            List<Contact> authContacts = contactMapper.queryContacts(uId);//获取授权用户的联系人信息
            if (registerContacts != null && registerContacts.size() > 0) {
                if (authContacts == null) {
                    authContacts = new ArrayList<>();
                }
                Message notify = new Message();
                notify.setType(Constant.PUSH_MESSAGE_ACCEPT_ADD_FRIEND);
                User targetUser = userMapper.selectByPrimaryKey(uId);
                for (Contact contact : authContacts) {
                    //判断注册用户的id在联系人关系中的位置
                    List<String> friendUid = new ArrayList<>();//创建一个集合用于存储授权好友联系人的id
                    if (StringUtils.equals(uId, contact.getmId())) {
                        friendUid.add(contact.gettId());
                    } else if (StringUtils.equals(uId, contact.gettId())) {
                        friendUid.add(contact.getmId());
                    }
                    Contact newContact = newContact(contact);
                    newContact.setTargetUser(targetUser);
                    notify.setExtraData(newContact);
                    notify.setCreated(new Date());
                    pushMessage(friendUid, notify);
                }
                for (Contact contact : registerContacts) {
                    //判断注册用户的id在联系人关系中的位置
                    List<String> friendUid = new ArrayList<>();//创建一个集合用于存储授权好友联系人的id
                    if (StringUtils.equals(registerUid, contact.getmId())) {
                        friendUid.add(contact.gettId());
                        contact.setmId(uId);
                    } else if (StringUtils.equals(registerUid, contact.gettId())) {
                        friendUid.add(contact.getmId());
                        contact.settId(uId);
                    }
                    //更新联系人关系
                    contactMapper.updateByPrimaryKeySelective(contact);
                    authContacts.add(contact);
                    Contact newCotact = newContact(contact);
                    newCotact.setTargetUser(targetUser);
                    notify.setExtraData(newCotact);
                    notify.setCreated(new Date());
                    pushMessage(friendUid, notify);
                }
            }
            //物理删除注册用户的信息
            deleteUserInfo(register);
            //封装返回给客户端的数据
            for (Contact contact : authContacts) {
                if (StringUtils.equals(uId, contact.gettId())) {
                    String tGroupName = contact.gettGroupName();
                    contact.setGroupName(tGroupName);
                }
            }
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("userInfo", authUser);
            resultMap.put("contacts", authContacts);
            return CommonResult.ok(resultMap);
        }
        //将设置的密码和手机号同步到redis中
        try {
            Map beanMap = EntityUtils.objectToMap_v1(bindUser);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, beanMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("replacePayPassword_1:实体类转map出错");
        }
        //将信息修改到数据库和第三方服务上
        logger.info("将绑定的信息同步到数据库和第三方服务上 uid:{}username:{},phone:{}", uId, bindUser.getUsername(), bindUser.getPhone());
        User tableUser = upDateUserInfo(bindUser);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("userInfo", tableUser);
        return CommonResult.ok(resultMap);
    }


    /**
     * 修改绑定的手机号
     * @param body
     * @return
     */
    @RequestMapping(value = "/modifyPhoneNumber", method = RequestMethod.POST)
    public CommonResult modifyPhoneNumber(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        logger.info("modifyPhoneNumber:" + uId);
        User updateUser = body.getObject("userInfo", User.class);
        String mobileCode = body.getString("mobileCode");

        //验证该账户的登录密码是否在24小时内修改过，如果修改过，禁止换手机号
        if (redisTemplate.hasKey("MODIFY_PASSWORD:" + uId)) {
            logger.warn("modifyPhoneNumber:24小时内修改过登录密码，禁止修改手机号" + uId);
            return CommonResult.build(Constant.FORBID_MODIFY_PHONE_NUMBER_24, "24小时内修改过登录密码，禁止更换手机号");
        }


        //验证 登录密码是否正确
        String originalPassword = (String) redisTemplate.opsForHash().get(Constant.USER_SESSION + uId, "password");
        if (!StringUtils.equals(originalPassword, DigestUtils.md5DigestAsHex(updateUser.getPassword().getBytes()))) {

            return CommonResult.build(Constant.PASS_WORD_WRONG, "密码错误");
        }
        //验证 验证码是否正确
        CommonResult result = checkMobileCode(mobileCode, updateUser.getPhone());
        if (result != null) {
            return result;
        }

        updateUser.setPassword(null);//清空密码，
        try {
            Map beanMap = EntityUtils.objectToMap_v1(updateUser);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, beanMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("replacePayPassword_1:实体类转map出错");
        }
        updateUser.setuId(uId);
        userMapper.updateByPrimaryKeySelective(updateUser);
        upDateUserInfo(updateUser);
        return CommonResult.ok();
    }

    @RequestMapping(value = "/updateUserInfo", method = RequestMethod.POST)
    public CommonResult updateUserInfo(@RequestBody User updateUser) {
        String uId = request.getHeader("uId");
        updateUser.setuId(uId);
        upDateUserInfo(updateUser);
        saveUserInfoToRedis(updateUser);
        return CommonResult.ok();
    }


    /**
     * 查询当前登录的用户id查询出好友列表
     *
     * @param token
     * @return
     */
    @Override
    @RequestMapping(value = "/getContacts", method = RequestMethod.GET)
    public CommonResult getContacts(@RequestParam("token") String token) {
        String uId = request.getHeader("uId");
        //查询redis中的联系人
        // Set<String> contacts = redisTemplate.opsForSet().members(CONTACT_KEY+user.getuId());
        //查询mysql中的联系人
        List<Contact> contacts = contactMapper.queryContacts(uId);
        for (Contact contact : contacts) {
            if (StringUtils.equals(uId, contact.gettId())) {
                String tGroupName = contact.gettGroupName();
                contact.setGroupName(tGroupName);
            }
        }
        return CommonResult.ok(contacts);
    }


    private User getUser(String uId) {
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + uId);
        if(entries.isEmpty()){
            return  userMapper.selectByPrimaryKey(uId);
        }
        return JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
    }


    @RequestMapping(value = "/follow", method = RequestMethod.POST)
    public CommonResult follow(@RequestBody String targetUid) {

        String uId = request.getHeader("uId");
        //检查是否给予关注,如果给过关注，就删除关注记录，如果没关注过，就保存关注记录
        Boolean member = redisTemplate.opsForSet().isMember(Constant.FOLLOW_RECORD + targetUid, uId);
        if (member) {
            redisTemplate.opsForSet().remove(Constant.FOLLOW_RECORD + targetUid, uId);
        } else {
            redisTemplate.opsForSet().add(Constant.FOLLOW_RECORD + targetUid, uId);
        }
        Map<String, Object> result = new HashMap<>();
        if (member) {
            result.put("isFollow", 0);
        } else {
            result.put("isFollow", 1);

        }
        return CommonResult.ok(result);
    }

    /**
     * 根据用户id获取用户信息
     * @param targetUid
     * @return
     */
    @RequestMapping(value = "/getUserInfo", method = RequestMethod.POST)
    public CommonResult getUserInfo(@RequestBody String targetUid) {
        logger.info("getUserInfo:" + targetUid);
        //  String uId = request.getHeader("uId");

        // Map<String, Object> result = new HashMap<>();
        //检查是否给予关注
//        Boolean member = redisTemplate.opsForSet().isMember(Constant.FOLLOW_RECORD + targetUid, uId);
//        if (member) {
//            result.put("isFollow", 1);
//        } else {
//            result.put("isFollow", 0);
//        }
//        //获取fans 数量
//        Long followSize = redisTemplate.opsForSet().size(Constant.FOLLOW_RECORD + targetUid);
//        result.put("followSize", followSize);

        //先查询是否有用户缓存信息，没有就从mysql 获取
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + targetUid);
        User user;
        if (entries.size() != 0) {
            user = JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
            user.setuId((String) entries.get("uId"));
            user.setAvatar((String) entries.get("avatar"));
            user.setuId((String) entries.get("uId"));
        } else {
            user = userMapper.selectByUid(targetUid);

        }

        if (user == null) {
            logger.error("getUserInfo:找不到用户信息，uid:{}", targetUid);
            return CommonResult.build(Constant.USER_NAME_INVALID, "找不到对应的用户信息");
        }
        return CommonResult.ok(user);
    }


    @GetMapping(value = "/getVersion")
    @SerializedField(encrypt = false)
    public CommonResult getVersion() {
        Map<String, Object> info = getVersionInfo();
        return CommonResult.ok(info);
    }

    @PostMapping("/syncUserInfo")
    public CommonResult syncUserInfo() {
        String uId = request.getHeader("uId");
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + uId);
        User user = new User(uId);
        try {
            user = JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //查询mysql中的联系人
        // List<Contact> contacts = contactMapper.queryContacts(uId);
        JSONObject result = new JSONObject();
        result.put("userInfo", user);
        // resultMap.put("contacts", contacts);
        return CommonResult.ok(result);
    }

    /**
     * 设置支付密码， 设置之前，先检查redis 中用户缓存是否有支付密码
     *
     * @return
     */
    @PostMapping("/setPayPassword")
    public CommonResult setPayPassword(@RequestBody User user) {
        String uId = request.getHeader("uId");
        user.setPayPassword(DigestUtils.md5DigestAsHex(user.getPayPassword().getBytes()));
        logger.info("setPayPassword:" + uId, user);
        Boolean isExist = redisTemplate.opsForHash().hasKey(Constant.USER_SESSION + uId, "payPassword");// TODO: 2018/10/25  检查该用户是否已经设置过 支付密码,也许这个是多余的考虑
        if (isExist) {
            return CommonResult.build(Constant.SETUP_PAY_PASSWORD_REPEAT, "已经设置过支付密码，不能直接覆盖");
        }
        user.setuId(uId);
        userMapper.updateByPrimaryKeySelective(user);
        try {
            Map beanMap = EntityUtils.objectToMap_v1(user);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, beanMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("setUpPayPassWord:实体类转map出错", e);
        }
        return CommonResult.ok();
    }

    /**
     * 修改支付密码
     *
     * @param body
     * @return
     */
    @PostMapping("/modifyPayPassword")
    public CommonResult modifyPayPassword(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        String oldPayPassword = body.getString("oldPayPassword");
        oldPayPassword = DigestUtils.md5DigestAsHex(oldPayPassword.getBytes());
        String newPayPassword = body.getString("newPayPassword");
        BigDecimal payLimit = null;
        if (body.containsKey("payLimit")) {//payLimit 有可能是空的，如果app端发现用户只是修改了支付密码，免密额度没改变的话，就不会上传  payLimit
            payLimit = body.getBigDecimal("payLimit");
        }
        String originalPayPassword = (String) redisTemplate.opsForHash().get(Constant.USER_SESSION + uId, "payPassword");

        if (!StringUtils.equals(oldPayPassword, originalPayPassword)) {
            return CommonResult.build(Constant.PAY_PASSWORD_ERROR, "修改支付密码失败，原支付密码错误");
        }
        User user = new User();
        user.setPayPassword(DigestUtils.md5DigestAsHex(newPayPassword.getBytes()));
        if (payLimit != null) {
            user.setPayLimit(payLimit);
        }
        try {
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, EntityUtils.objectToMap_v1(user));//缓存进redis
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("replacePayPassword:实体类转map出错", e);
        }
        user.setuId(uId);
        userMapper.updateByPrimaryKeySelective(user);

        return CommonResult.ok();
    }


    /**
     *检查支付密码
     * @param user
     * @return
     */
    @PostMapping("/retrievePayPassword")
    public CommonResult retrievePayPassword(@RequestBody User user) {

        String uId = request.getHeader("uId");
        logger.info("validatePassword:" + uId);

        //验证该账户的登录密码是否在24小时内修改过，如果修改过，禁止通过登录密码修改支付密码
        if (redisTemplate.hasKey("MODIFY_PASSWORD:" + uId)) {
            logger.warn("retrievePayPassword:24小时内修改过登录密码，禁止通过登录密码修改支付密码" + uId);
            return CommonResult.build(Constant.FORBID_MODIFY_PAY_PASSWORD_24, "24小时内修改过登录密码，禁止通过登录密码修改支付密码");
        }

        //查询redis,判断该 用户 是否因连续输入登录密码错误，被禁止 通过登录密码  重置支付密码
        Object retrievePayPasswordCountObject = redisTemplate.opsForValue().get("RETRIEVE_COUNT:" + uId);
        if (retrievePayPasswordCountObject != null) {
            int retrievePayPasswordCount = (int) retrievePayPasswordCountObject;
            if (retrievePayPasswordCount > retrievePayPasswordErrorLimit) {
                logger.warn("restLogin:登录密码错误超过限制，账户进入锁定状态  " + uId);
                Long expire = redisTemplate.getExpire("RETRIEVE_COUNT:" + uId, TimeUnit.MINUTES);
                return CommonResult.build(Constant.RETRIEVE_PAY_PASSWORD_ERROR_LIMIT, String.format("连续登录尝试超过%s次限制", retrievePayPasswordErrorLimit), expire);
            } else if (retrievePayPasswordCount == retrievePayPasswordErrorLimit) {
                // 当错误登录次数等于限制次数的时候，把错误次数设置为 错误次数上限+1，过期时间设置为 预设的 账户锁定时间
                logger.warn("restLogin:登录密码错误超过限制，账户进入锁定状态  " + uId);
                redisTemplate.opsForValue().set("RETRIEVE_COUNT:" + uId, (retrievePayPasswordErrorLimit + 1), accountLockExpire, TimeUnit.HOURS);
                return CommonResult.build(Constant.RETRIEVE_PAY_PASSWORD_ERROR_LIMIT, String.format("连续登录尝试超过%s次限制", retrievePayPasswordErrorLimit), accountLockExpire * 60);
            }
        }

        String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        //获取缓存中的登录密码
        String originalPassword = (String) redisTemplate.opsForHash().get(Constant.USER_SESSION + uId, "password");
        if (!StringUtils.equals(password, originalPassword)) {

            //当密码错误，记录该账户的错误次数
            Long passwordErrorCount = 1L;
            if (retrievePayPasswordCountObject == null) {//第一次 登录密码错误
                redisTemplate.opsForValue().set("RETRIEVE_COUNT:" + uId, 1 + "", passwordErrorCountExpire, TimeUnit.MINUTES);
            } else {
                passwordErrorCount = redisTemplate.opsForValue().increment("RETRIEVE_COUNT:" + uId, 1L);
            }

            return CommonResult.build(Constant.PASS_WORD_WRONG, "密码错误", retrievePayPasswordErrorLimit - passwordErrorCount);
        }

        user.setPassword(null);
        user.setPayPassword(DigestUtils.md5DigestAsHex(user.getPayPassword().getBytes()));
        if (user.getPayLimit() != null) {
            try {
                Map beanMap = EntityUtils.objectToMap_v1(user);
                redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, beanMap);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("validatePassword:实体类转Map出错", e);
            }
        } else {
            redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, "payPassword", user.getPayPassword());
        }
        user.setuId(uId);
        userMapper.updateByPrimaryKeySelective(user);
        return CommonResult.ok();
    }

    /**
     * 获取人工服务的用户id ,用人工找回密码等服务
     *
     * @return
     */
    @GetMapping("/customerService")
    @SerializedField(encrypt = false)
    public CommonResult customerService() {
        User manualServiceUser = null;
        Map beanMap = redisTemplate.opsForHash().entries(Constant.USER_SESSION + MytxConfig.manualServiceId);
        if (beanMap != null && beanMap.size() != 0) {
            manualServiceUser = JSON.parseObject(JSONObject.toJSONString(beanMap), User.class);
        }
        if (manualServiceUser != null) {
        } else {
            manualServiceUser = userMapper.selectByUid(MytxConfig.manualServiceId);
            manualServiceUser.setuId(MytxConfig.manualServiceId);
        }
        return CommonResult.ok(manualServiceUser);
    }


    private void saveUserInfoToRedis(@RequestBody User user) {
        try {
            Map map = EntityUtils.objectToMap_v1(user);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + user.getuId(), map);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("restLogin:缓存用户信息失败：" + e.getMessage());
        }
    }


    private void pushMessage(List<String> userIdList, Message notify) {
        JSONObject info = new JSONObject();
        info.put("userIdList",userIdList);
        info.put("message",notify);
        redisTemplate.convertAndSend(Constant.NOTIFY_PUSH_MESSAGE,info );
    }


    /**
     * 验证码的正确性
     * @param mobileCode
     * @param phone
     * @return
     */
    private CommonResult checkMobileCode(@RequestParam("MOBILE_CODE") String mobileCode, String phone) {
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(mobileCode)) {
            logger.error("短信验证出错：验证码或者手机号为空");
            return CommonResult.build(400, "短信验证码或者手机号为空");

        }
        String mobileCodeKey = Constant.MOBILE_CODE + phone;
        Object code = redisTemplate.opsForValue().get(mobileCodeKey);
        //从redis中没获取到该手机号的短信验证码，可能是过期了，直接return
        if (code == null) {
            logger.info("checkMobileCode:短信验证码过期 " + phone + "验证码：" + mobileCode);
            return CommonResult.build(Constant.MOBILE_CODE_EXPIRE, "短信验证码过期");
        }
        //如果查到的 验证码 包含"-" ，说明此手机号最近一次发的验证码 已经被使用，
        if (code instanceof String) {

            if (((String) code).contains("-")) {
                // if (MOBILE_CODE.equals(code.substring(0, code.indexOf("-")))) {
                logger.info("checkMobileCode:短信验证码已经被使用 " + phone + "验证码：" + mobileCode);
                return CommonResult.build(Constant.MOBILE_CODE_USED, "验证码已经被使用");
//            } else {
//                return CommonResult.build(400, MOBILE_CODE_ERROR);
//            }
            }
        }
        //获取到redis中的短信验证码，和请求携带的做对比，对不上，返回错误
        if (!mobileCode.equals(String.valueOf(code))) {
            logger.info("checkMobileCode:短信验证码错误 " + phone + "验证码：" + mobileCode);
            return CommonResult.build(Constant.MOBILE_CODE_ERROR, "验证码错误");
        }
        //验证码匹配上了，此验证码被消费掉，设置验证码为0
        redisTemplate.opsForValue().set(mobileCodeKey, code + "-", 20, TimeUnit.MINUTES);
        return null;
    }

    /**
     * 关注
     * 粉丝Key：followUID
     * fansStaffID
     *
     * @param
     * @return
     */
    @PostMapping("/specialAttention")
    @SerializedField(encrypt = false)
    public CommonResult specialAttention(@RequestBody JSONObject body) {
        String followUId = body.getString("followUId");
        String uId = body.getString("uId");
        redisTemplate.opsForSet().add(Constant.USER_FOLLOW_LIST + uId, followUId);
        redisTemplate.opsForSet().add(Constant.USER_FANS_LIST + followUId, uId);
        logger.info("specialAttention:followUId{}，uid{}", followUId, uId);
        return CommonResult.ok();

    }

    /**
     * 检查是否关注 返回用户关注数 粉丝数
     *
     * @param body
     * @return
     */
    @PostMapping("/checkSpecialAttention")
    @SerializedField(encrypt = false)
    public CommonResult checkSpecialAttention(@RequestBody JSONObject body) {
        String fansUId = body.getString("followUId");
        String uId = body.getString("uId");
        Long fansNum = redisTemplate.opsForSet().size(Constant.USER_FANS_LIST + uId);
        Long followNum = redisTemplate.opsForSet().size(Constant.USER_FOLLOW_LIST + uId);
        logger.info("specialAttention:followUId{}，uid{}", fansUId, uId);
        JSONObject data = new JSONObject();
        if (fansUId != null) {
            Boolean isFollow = redisTemplate.opsForSet().isMember(Constant.USER_FOLLOW_LIST + fansUId, uId);
            data.put("isFollow", isFollow);
        }
        data.put("fansNum", fansNum);
        data.put("followNum", followNum);

        return CommonResult.ok(data);

    }

    /**
     * 取消关注
     *
     * @param body
     * @return
     */
    @PostMapping("/removeSpecialAttention")
    @SerializedField(encrypt = false)
    public CommonResult removeSpecialAttention(@RequestBody JSONObject body) {
        String followUId = body.getString("followUId");
        String uId = body.getString("uId");
        redisTemplate.opsForSet().remove(Constant.USER_FOLLOW_LIST + uId, followUId);
        redisTemplate.opsForSet().remove(Constant.USER_FANS_LIST + followUId, uId);
        logger.info("specialAttention:followUId{}，uid{}", followUId, uId);
        return CommonResult.ok();


    }

    /**
     * 加载 关注、粉丝列表
     *
     * @param body
     * @return
     */
    @PostMapping("/loadFollowFansList")
    @SerializedField(encrypt = false)
    public CommonResult loadFollowFansList(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");//当前登录用户id
        String targetUserId = body.getString("uId");//要查询的目标用户id
        boolean type = body.getBoolean("isShowFans");
        int page = 1;
        int size = 10;
        if (body.containsKey("page")) {
            page = body.getInteger("page");
        }
        if (body.containsKey("size")) {
            size = body.getInteger("size");
        }
        PageInfo pageInfo = null;
        List<User> users = null;
        if (type) {
            Set fansSet = redisTemplate.opsForSet().members(Constant.USER_FANS_LIST + targetUserId);
            if (fansSet == null || fansSet.size() == 0) {
                return CommonResult.ok();
            }
            List<String> fanslist = new ArrayList<>(fansSet);
            PageHelper.startPage(page, size);
            users = userMapper.selectUserByIds(fanslist);
            pageInfo = new PageInfo<>(users);

        } else {
            Set followSet = redisTemplate.opsForSet().members(Constant.USER_FOLLOW_LIST + targetUserId);
            if (followSet == null || followSet.size() == 0) {
                return CommonResult.ok(pageInfo);
            }
            PageHelper.startPage(page, size);
            List<String> followlist = new ArrayList<>(followSet);

            users = userMapper.selectUserByIds(followlist);
            pageInfo = new PageInfo<>(users);

        }
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            String fansUId = user.getuId();
            Boolean isFollow = redisTemplate.opsForSet().isMember(Constant.USER_FOLLOW_LIST + uId, fansUId);
            user.setFollow(isFollow);
        }
        return CommonResult.ok(pageInfo);
    }

    private void registerThirdPartyService(User user, String phone) {
        //保存用户信息到ES
        Topic userInfoTopic = new Topic();
        userInfoTopic.setId(user.getuId());//让保存用户信息的topic id 和用户id 相同
        userInfoTopic.setType(Constant.TOPIC_TYPE_USER_INFO);
        User saveToES = new User();
        saveToES.setuId(user.getuId());
        saveToES.setUsername(user.getUsername());
        saveToES.setPhone(phone);
        userInfoTopic.setManager(saveToES);
        try {
            JSONObject body = new JSONObject();
            body.put("topic", userInfoTopic);
            searchService.index(body);
            logger.info("restRegister:保存新用户信息到ES成功" + user.getuId());
        } catch (Exception e) {
            logger.error("restRegister:保存新用户信息到ES 出错，uId:{}", user.getuId());
        }

    }

    /**
     * 将一个Contact复制给另一个类
     *
     * @param contact
     * @return
     */
    private Contact newContact(Contact contact) {
        Contact newContact = new Contact();
        BeanUtils.copyProperties(contact, newContact);
        return newContact;
    }

    /**
     * 将授权用户的数据同步到原始用户中
     * @param authUser
     * @param originalUserInfo
     * @param bindUser
     */
    private void authSetOriginalUser(User authUser,User originalUserInfo,User bindUser){
        BigDecimal authBalace = authUser.getBalance();
        BigDecimal registerBalace = originalUserInfo.getBalance();
        BigDecimal authDeposit = authUser.getDeposit();
        BigDecimal registerDeposit = originalUserInfo.getDeposit();
        logger.info("注册用户的余额:registerBalace:{},注册用户的保证金:registerDeposit:{}", registerBalace, registerDeposit);
        logger.info("授权用户的余额:authBalact:{},注册用户的保证金:authDeposit:{}", authBalace, authDeposit);
        if(authBalace!=null){
            originalUserInfo.setBalance(authBalace.add(registerBalace));
        }
        if(authDeposit!=null) {
            originalUserInfo.setDeposit(authDeposit.add(registerDeposit));
        }
        originalUserInfo.setUsername(bindUser.getUsername());
        //如果当前授权账号的密码和原始账户密码不一致，需要去更原始账户阿里云旺的登录密码
        if (!StringUtils.equals(bindUser.getPassword(), originalUserInfo.getPassword())) {
            originalUserInfo.setPassword(bindUser.getPassword());
            //  updat eUserInfoToAli(bindUserInfo);
        }
        originalUserInfo.setGender(authUser.getGender());
        originalUserInfo.setNick(authUser.getNick());
        originalUserInfo.setAliUid(authUser.getAliUid());
        originalUserInfo.setAvatar(authUser.getAvatar());
        originalUserInfo.setArea(authUser.getArea());
        if (authUser.getPayPassword() != null) {
            originalUserInfo.setPayPassword(authUser.getPayPassword());
        }
        if (authUser.getPayLimit() != null) {
            originalUserInfo.setPayLimit(authUser.getPayLimit());
        }
        BigDecimal authDonationAmount = authUser.getDonationAmount();
        BigDecimal registerDonationAmout = originalUserInfo.getDonationAmount();
        BigDecimal authDonationBalance = authUser.getDonationBalance();
        BigDecimal registerDonationBalance = originalUserInfo.getDonationBalance();
        BigDecimal authDonationReceived = authUser.getDonationReceived();
        BigDecimal registerDonationReceived = originalUserInfo.getDonationReceived();
        logger.info("注册用户的registerDonationAmout:{},注册用户的registerDonationBalance:{},注册用户的registerDonationReceived:{}",
                registerDonationAmout, registerDonationBalance, registerDonationReceived);
        logger.info("授权用户的authDonationAmout:{},授权用户的authDonationBalance:{},授权用户的authDonationReceived:{}",
                authDonationAmount, authDonationBalance, authDonationReceived);
        if(authDonationAmount!=null) {
            originalUserInfo.setDonationAmount(authDonationAmount.add(registerDonationAmout));
        }
        if(authDonationBalance!=null) {
            originalUserInfo.setDonationBalance(authDonationBalance.add(registerDonationBalance));
        }
        if(authDonationReceived!=null) {
            originalUserInfo.setDonationReceived(authDonationReceived.add(registerDonationReceived));
        }
        originalUserInfo.setUpdated(new Date());
    }

    /**
     * 将数据库中联系人分组信息映射到前端
     */
    private void mappingGroupName(List<Contact> registerContacts,String uid){
        if (registerContacts != null && registerContacts.size() > 0) {
            //将数据库中的分组信息映射到前端
            for (Contact contact : registerContacts) {
                if (StringUtils.equals(uid, contact.gettId())) {
                    String tGroupName = contact.gettGroupName();
                    contact.setGroupName(tGroupName);
                }
            }
        }
    }

    /**
     *获取推送用户更新消息的好友id
     */
    private List<String> addFrindUserMessage( List<Contact> contacts,String uId ){
        List<String> userIdList = new ArrayList<>();
        //通知更新用户的好友刷新好友列表信息
        for (Contact contact : contacts) {
            if (StringUtils.equals(contact.getStatus(), Constant.CONTACT_STATUS_MUTUAL)) {
                if (StringUtils.equals(uId, contact.getmId())) {
                    userIdList.add(contact.gettId());
                } else if (StringUtils.equals(uId, contact.gettId())) {
                    userIdList.add(contact.getmId());
                }
            }
        }
        return userIdList;
    }
}
